
#ifndef __audio_openalH__
#define __audio_openalH__

#include "config.h"

#ifdef __AUDIO_OPENAL__

#include "data.h"
#include "dator.h"
#include "physics.h"
#include "buf.h"
#include <AL/al.h>
#include <AL/alc.h>

namespace WtfAudio {
	/**
	 * The base class for loading audio data from specific formats.
	 **/
	class Data: public WtfEngine::DataObject {
	public:
		typedef enum {
			AUDIODATA_MONO_8 = AL_FORMAT_MONO8,
			AUDIODATA_MONO_16 = AL_FORMAT_MONO16,
			AUDIODATA_STEREO_8 = AL_FORMAT_STEREO8,
			AUDIODATA_STEREO_16 = AL_FORMAT_STEREO16,
			AUDIODATA_INTERNAL
		} tDataType;

	protected:
		/// The PCM format
		tDataType mFormat;
		int mBitRate;

		inline Data(const WtfEngine::StringPool::Entry& sName): WtfEngine::DataObject(sName) {};

	public:
		virtual bool getData(WtfEngine::NonCopyBuffer<>::tRefa rBuffer) = 0;
		virtual void Reset() = 0;

		inline tDataType getFormat() const {
			return mFormat;
		};
		inline int getBitRate() const {
			return mBitRate;
		};

		DATA_OBJECT(Data, sizeof(Data));
	};

	class AudioSample: public WtfEngine::GcObject {
		ALuint		mBuffer;
		unsigned	muSize;
		Data::tRef mrData;

	public:
		AudioSample(const Data::tRef& rData)
		: WtfEngine::GcObject(), mBuffer(0), muSize(0), mrData(rData) {};
		~AudioSample();

		// OpenAL specific
		ALuint getBuffer() const {
			return mBuffer;
		};

		GC_AUTOSIZE(AudioSample);
	};

	/**
	 * Audio files are referred to by settings (i.e. logical names which
	 * map to real files, e.g. "sfx_cannon_shot" -> "media/sfx/cannon1.wav")
	 **/
	typedef WtfEngine::Setting<AudioSample::tRef>	tAudio;
	typedef tAudio::tCacheRef					tAudioRef;

	
	/**
	 * The sound base class. Sounds are purely client-side objects -
	 * they are not shared to other peers on the network, as the same logic
	 * running on each node will produce the same sounds.
	 **/
	class BaseSound: public WtfEngine::GcObject {
	protected:
		AudioSample::tRef	mrAudioSample;
		ALuint				mSource;

		public:
			BaseSound(tAudioRef& rAudioSample);

			void Play(bool bLoop = false);
			void Destroy();

		GC_AUTOSIZE(BaseSound);
	};

	/**
	 * This is the class for streaming music and other persistent sounds. It streams
	 * data directly from the data source, so it can manage its own OpenAL buffers.
	 **/
	class AudioStream: public WtfEngine::GcObject, public virtual WtfEngine::IDynamic {
		Data::tRef mrData;
		WtfEngine::NonCopyBuffer<>::tRef mrBuffer;
		ALuint mSource;
		bool mbLoop;

	public:
		AudioStream(const Data::tRef& rData, unsigned uBufSize = 4096);

		void Play(bool bLoop = false);
		void Stop();
		void Update();

		bool IsPlaying() const;

		GC_AUTOSIZE(AudioStream);
	};

	/**
	 * A sound which is played (on loop) at a static point in the world.
	 **/
	class StaticWorldSound: public BaseSound {

	public:
		StaticWorldSound(tAudioRef& rAudioSample, const tPosition& vPosition);

	};

	/**
	 * Manages and wraps the OpenAL device and context.
	 **/
	class AudioMixer : public WtfEngine::Task<AudioMixer>, public WtfEngine::Loggable<AudioMixer>
	{
		ALCdevice * mpDevice;
		ALCcontext *mpContext;

		std::vector<BaseSound::tRef> mvrPlayingSounds;

		protected:
			void Run();

			friend class BaseSound;
			friend class AudioSample;

		public:
			AudioMixer();
			~AudioMixer();

			static bool CheckError(bool bThrowException);
	};
};


#endif
#endif
